package zsl.run;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import org.apache.poi.ss.formula.functions.Code;

import zsl.algo.MergeAlgo;
import zsl.algo.TAAlgo;
import zsl.generator.DefaultWordListGenerator;
import zsl.generator.UniformWordListGenerator;
import zsl.generator.WordListGenerator;
import zsl.output.ExcelWriter;
import zsl.utils.MergeTimeInfo;
import zsl.utils.RunningTimeInfo;
import zsl.utils.TAInfo;
import zsl.utils.WordCount;
import zsl.utils.WordCountList;

public class Run {
	
	public static void main(String[] args) throws IOException {
		Run run = new Run();
		run.writeRunningTimeInfo();
	}
	
	public void writeRunningTimeInfo() throws IOException{
		final int WARM_TIME = 0;
		final int REPEAT_TIME = 3;
		final long SEED = 1000L;
		final int TOPK = 10;
		
		// factors that may influence 
		int[] numOfWordsArray = {1000,2500,5000,7500,10000};
		int[] numOfListsArray = {200, 400,600};
		
		for (int wordArrayIndex = 0; wordArrayIndex < numOfWordsArray.length; wordArrayIndex++) {
			int dictLen = numOfWordsArray[wordArrayIndex];
			WordListGenerator wg = new UniformWordListGenerator(dictLen, SEED);
			ExcelWriter mergeWriter = new ExcelWriter();
//			ExcelWriter runTimeWriter = new ExcelWriter();
			//start loop over numOfListsArray
			for (int listArrayIndex = 0; listArrayIndex < numOfListsArray.length; listArrayIndex++) {
				
				int numOfWords = numOfWordsArray[wordArrayIndex];
				int numOfLists = numOfListsArray[listArrayIndex];
				
				//generate lists of words
				Vector<WordCountList> lists = new Vector<>();
				for (int j = 0; j < numOfLists; j++) {
					lists.add(wg.generateWords(numOfWords));
				}
				
				System.out.println("before merge, numOfWordsPerList=" + numOfWords + "; numOfLists=" + numOfLists+"\n");
				int maxMergeNum =(int) Math.ceil(numOfLists/2.0);
				long start,end;
				double mergeTime = 0, taTime = 0;
				List<RunningTimeInfo> infos = new LinkedList<>();
				List<TAInfo> taInfos = new LinkedList<>(); 
				List<MergeTimeInfo> mergeTimeInfos = new ArrayList<>(200);
				for (int j = maxMergeNum; j > 1; j--) {
					if (isValidBestMerge(j, numOfLists)) {
						System.out.println("=======mergeNum " + j +"===========");
						mergeTime = 0;
						MergeTimeInfo mInfo = new MergeTimeInfo();
						Vector<WordCountList> mergedList = null;
						//warm up
						for (int warm = 0; warm < WARM_TIME; warm++) {
							mergedList = MergeAlgo.merge(lists, j, mInfo);
						}
						//repeat
						mInfo = new MergeTimeInfo();
						start = System.currentTimeMillis();
						for (int repeat = 0; repeat < REPEAT_TIME; repeat++) {
							mergedList = MergeAlgo.merge(lists, j, mInfo);
						}
						end = System.currentTimeMillis();
						mergeTime = (end-start) / REPEAT_TIME;
						mInfo.setTotal(mergeTime);
						mInfo.setMergeTime(mInfo.getMergeTime()/REPEAT_TIME);
						mInfo.setAddedMergeTime(mInfo.getAddedMergeTime()/REPEAT_TIME);
						mInfo.setAddedSortTime(mInfo.getAddedSortTime()/REPEAT_TIME);
						mInfo.setListNum(mergedList.size());
						
						mergeTimeInfos.add(mInfo);
						
						//Code with taInfos
						
//						taTime = 0;
//						
//						TAInfo taInfo = null;
//						for (int repeat = 0; repeat < REPEAT_TIME; repeat++) {
//							taInfo = new TAInfo();
//							start = System.currentTimeMillis();
//							ArrayList<WordCount> topKList = TAAlgo.getTopK(TOPK, mergedList, taInfo, false); 
//							end = System.currentTimeMillis();
//							taTime += (end - start);
//						}
//						taTime = taTime / REPEAT_TIME;
//						
//						infos.add(new RunningTimeInfo(mergedList.size(), taTime, mergeTime));
//						taInfos.add(taInfo);
						
						
						
//						start = System.nanoTime();
//						for (int repeat = 0; repeat < REPEAT_TIME; repeat++) {
//							TAAlgo.getTopK(TOPK, mergedList, null, false);
//						}
//						end = System.nanoTime();
//						taTime = end-start / REPEAT_TIME;
//						infos.add(new RunningTimeInfo(mergedList.size(), taTime, mInfo.getMergeTime()+mInfo.getAddedMergeTime()+mInfo.getAddedSortTime() ));
					}
				}
//				runTimeWriter.addRunningTimeInfoSheet(""+numOfLists,  infos, null);//taInfos not used
				mergeWriter.addMergeTimeSheet(""+numOfLists, mergeTimeInfos);
			}//end loop over numOfListsArray
			String name = wg.getClass().getName();
			mergeWriter.write2Excel(name.substring(name.lastIndexOf('.')+1, name.length())+"-MTAnalysis-W"+numOfWordsArray[wordArrayIndex]+"-8-6-valideMergeNum-HashMapWarmup-Djava.compiler=NONE200400600.xlsx");
//			runTimeWriter.write2Excel(name.substring(name.lastIndexOf('.')+1, name.length())+"-RT-W"+numOfWordsArray[wordArrayIndex]+"-8-5-hashMapWarmupPerGet2468-Djava.compiler=NONE.xlsx");
		}//end loop over numOfWordsArray
	}
	
	private static String getEachLenght(Vector<WordCountList> lists){
		String result = "";
		for (WordCountList wordCountList : lists) {
			result += wordCountList.size()+", ";
		}
		return result;
	}
	
	private static boolean isValidBestMerge(int mergeNum, int listNumBeforeMerge){
		return Math.ceil(listNumBeforeMerge / (double)mergeNum) != Math.ceil(listNumBeforeMerge / (double)(mergeNum-1));
	}
}
